package client

import (
	"context"
	"github.com/gogf/gf/v2/crypto/gmd5"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/grand"
	"meta-self/internal/consts"
	"meta-self/internal/dao"
	"meta-self/internal/model"
	"meta-self/internal/model/entity"
	"meta-self/internal/model/input/clientin"
	"meta-self/internal/pkg/token"
	"meta-self/internal/service"
	"meta-self/utility/simple"
)

type sClientAuth struct{}

func init() {
	service.RegisterClientAuth(&sClientAuth{})
}

// Register 客户端注册
func (s *sClientAuth) Register(ctx context.Context, in *clientin.RegisterInp) (result *clientin.RegisterModel, err error) {
	// 1. 检查用户名和手机号是否已存在
	if count, err := dao.SysUsers.Ctx(ctx).Where(dao.SysUsers.Columns().Username, in.Username).Count(); err != nil || count > 0 {
		return nil, gerror.New("用户名已存在")
	}
	if count, err := dao.SysUsers.Ctx(ctx).Where(dao.SysUsers.Columns().PhoneNum, in.PhoneNum).Count(); err != nil || count > 0 {
		return nil, gerror.New("手机号已存在")
	}
	// 2. 创建用户记录
	user := &entity.SysUsers{
		Username: in.Username,
		PhoneNum: in.PhoneNum,
		Wechat:   in.Wechat,
		NickName: in.NickName,
		Type:     consts.UserTypeMember,
		Status:   consts.StatusEnabled,
	}
	user.Salt = grand.S(6)
	user.Password = gmd5.MustEncryptString(in.Password + user.Salt)
	if user.Id, err = dao.SysUsers.Ctx(ctx).Data(user).InsertAndGetId(); err != nil {
		return nil, gerror.Wrap(err, "注册失败，请联系管理员")
	}
	result = &clientin.RegisterModel{
		Id:       user.Id,
		Username: user.Username,
	}
	return
}

// Login 客户端登录
func (s *sClientAuth) Login(ctx context.Context, in *clientin.LoginInp) (res *clientin.LoginModel, err error) {
	var mb *entity.SysUsers
	if err = dao.SysUsers.Ctx(ctx).Where(dao.SysUsers.Columns().Username, in.Username).Scan(&mb); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if mb == nil {
		err = gerror.New("账号不存在")
		return
	}

	res = new(clientin.LoginModel)
	res.Id = mb.Id
	res.Username = mb.Username
	if mb.Salt == "" {
		err = gerror.New("用户信息错误")
		return
	}

	if err = simple.CheckPassword(in.Password, mb.Salt, mb.Password); err != nil {
		return
	}

	if mb.Status != consts.StatusEnabled {
		err = gerror.New("账号已被禁用")
		return
	}

	res, err = s.handleLogin(ctx, mb)
	return
}

// handleLogin .
func (s *sClientAuth) handleLogin(ctx context.Context, mb *entity.SysUsers) (res *clientin.LoginModel, err error) {
	user := &model.Identity{
		Id:       mb.Id,
		Username: mb.Username,
		NickName: mb.NickName,
		Email:    mb.Email,
		PhoneNum: mb.PhoneNum,
		App:      "client",
		LoginAt:  gtime.Now(),
	}

	lt, expires, err := token.Login(ctx, user)
	if err != nil {
		return nil, err
	}

	res = &clientin.LoginModel{
		Username: user.Username,
		Id:       user.Id,
		Token:    lt,
		Expires:  expires,
	}
	return
}
